package com.molichuxing.services.delay;

import java.net.UnknownHostException;
import java.util.List;
import java.util.concurrent.DelayQueue;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;
import com.molichuxing.framework.contants.RedisKeyConst;
import com.molichuxing.framework.exception.BizException;
import com.molichuxing.framework.utils.DingTalkUtil;
import com.molichuxing.framework.utils.RedisUtil;
import com.molichuxing.services.business.dto.request.modify.OrderTradeCancelModifyBizDto;
import com.molichuxing.services.business.service.OrderTradeBizService;
import com.molichuxing.services.business.service.impl.OrderDelayBizServiceImpl;
import com.molichuxing.services.property.OrderStatusFlowModifiedTypeEnum;

/**
 * 订单延时任务
 * 
 * @author zoumingyu
 * @date 2019年11月7日
 *
 */
@Component
public class OrderDelayTask {
	private static final Logger logger = LoggerFactory.getLogger(OrderDelayBizServiceImpl.class);

	@Value("${profiles.active}")
	private String ACTIVE;

	@Value("${profiles.active.explain}")
	private String ACTIVE_EXPLAIN;

	private boolean start;

	private String DELAY_ORDER_KEY;

	public DelayQueue<OrderDelay> delayQueue = new DelayQueue<>();

	@Resource
	private RedisUtil redisUtil;

	@Resource
	private OrderTradeBizService orderTradeBizService;

	private class TakeOrder implements Runnable {
		@Override
		public void run() {
			while (true) {
				OrderDelay orderDelay = null;
				try {
					orderDelay = delayQueue.take();
					// 处理到期订单
					OrderDelayTask.this.processOrderDelay(orderDelay);
				} catch (Exception e) {
					logger.error("延时订单处理异常：" + JSONObject.toJSONString(orderDelay), e);
					DingTalkUtil.exceptionSend(
							ACTIVE_EXPLAIN + "延时订单(" + orderDelay.getOrderCode() + ")处理异常:" + e.getMessage());
				}
			}
		}
	}

	/**
	 * 新增延时任务
	 * 
	 * @param createDto
	 * @return
	 */
	public boolean create(OrderDelay orderDelay) {
		logger.info("[create]新增延时任务：" + orderDelay.toString());
		delayQueue.put(orderDelay);
		// 添加redis延时
		redisUtil.set(DELAY_ORDER_KEY + orderDelay.getOrderCode(),
				JSONObject.toJSONString(orderDelay));
		return true;
	}

	/**
	 * 删除延时任务
	 * 
	 * @param orderCode
	 *            订单号
	 * @return
	 */
	public boolean delete(Long orderCode) {
		logger.info("[delete]删除延时任务：" + orderCode);
		boolean result = true;
		// 查询redis是否存在
		String orderDelayStr = redisUtil.get(DELAY_ORDER_KEY + orderCode);
		if (orderDelayStr == null) {
			// 不存在，不用删除
			return result;
		}
		// 存在，移除延时队列
		OrderDelay orderDelay = JSONObject.parseObject(orderDelayStr, OrderDelay.class);
		// 移除
		delayQueue.remove(orderDelay);
		// 删除redis保存信息
		redisUtil.del(DELAY_ORDER_KEY + orderCode);

		return result;
	}

	/**
	 * 处理延时任务
	 * 
	 * @param orderDelay
	 */
	private void processOrderDelay(OrderDelay orderDelay) {
		// 查询是否存在redis
		String orderDelayStr = redisUtil.get(DELAY_ORDER_KEY + orderDelay.getOrderCode());
		if (orderDelayStr == null) {
			// 不存在
			return;
		}
		// 删除redis
		redisUtil.del(DELAY_ORDER_KEY + orderDelay.getOrderCode());

		try {
			// 取消订单
			OrderTradeCancelModifyBizDto modifyBizDto = new OrderTradeCancelModifyBizDto();
			modifyBizDto.setOrderCode(orderDelay.getOrderCode());
			modifyBizDto.setUserId(orderDelay.getUserId());
			modifyBizDto.setModifiedType(OrderStatusFlowModifiedTypeEnum.B_USER);
			modifyBizDto.setOperateId(0);
			modifyBizDto.setOperateName("system");
			orderTradeBizService.modifyCancel(modifyBizDto);
		} catch (BizException e) {
			logger.error("处理延时任务取消订单(" + orderDelay.getOrderCode() + ")失败：", e);
		} catch (Exception e) {
			logger.error("处理延时任务取消订单(" + orderDelay.getOrderCode() + ")异常：", e);
			DingTalkUtil.exceptionSend(
					ACTIVE_EXPLAIN + "删除延时任务取消订单(" + orderDelay.getOrderCode() + ")异常:" + e.getMessage());
			// 重新存入redis，等待人工处理
			redisUtil.set(DELAY_ORDER_KEY + orderDelay.getOrderCode(), orderDelayStr);
		}
	}

	/**
	 * redis中获取所有延时任务
	 */
	private void redisOrderDelay() {
		// 获取所有的延时订单
		List<String> keys = redisUtil.scan(DELAY_ORDER_KEY + "*");
		if (keys == null || keys.isEmpty()) {
			return;
		}
		for (String key : keys) {
			String value = redisUtil.get(key);
			OrderDelay orderDelay = JSONObject.parseObject(value, OrderDelay.class);
			delayQueue.put(orderDelay);
		}
	}

	@PostConstruct
	public void init() throws UnknownHostException {
		if (start) {
			return;
		}
		logger.info("****************启动TakeOrder线程start****************");
		DELAY_ORDER_KEY = RedisKeyConst.DELAY_ORDER_KEY + ACTIVE + "_";
		// 从redis中获取到未处理的延时订单
		redisOrderDelay();
		// 启动延时队列线程
		new Thread(new TakeOrder()).start();
		start = true;
		logger.info("****************启动TakeOrder线程end****************");
	}

}
